package com.gjy.util.basic;

import com.google.gson.*;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-06-19 14:49:31
 */
public class JsonFieldFinders {

    private static final Gson gson = new GsonBuilder().create();

    /**
     * 按路径（如"a[0].b.c"）查找嵌套字段值，支持数组下标
     *
     * @param json JSON字符串
     * @param path 路径（如"a[0].b.c"）
     * @param type 返回值类型
     * @return 匹配的字段值，未找到返回null
     */
    public static <T> T findFieldByPath(String json, String path, Class<T> type) {
        if (json == null || path == null || path.isEmpty()) return null;
        JsonElement element = JsonParser.parseString(json);
        String[] tokens = path.split("\\.");
        for (String token : tokens) {
            // 处理数组下标，如 a[0]
            if (token.matches("(.+)\\[(\\d+)]")) {
                String key = token.replaceAll("\\[(\\d+)]", "");
                int idx = Integer.parseInt(token.replaceAll(".*\\[(\\d+)]", "$1"));
                if (!element.isJsonObject()) return null;
                element = element.getAsJsonObject().get(key);
                if (element == null || !element.isJsonArray()) return null;
                if (element.getAsJsonArray().size() <= idx) return null;
                element = element.getAsJsonArray().get(idx);
            } else {
                if (!element.isJsonObject()) return null;
                element = element.getAsJsonObject().get(token);
            }
            if (element == null) return null;
        }
        if (element == null || element.isJsonNull()) return null;
        return gson.fromJson(element, type);
    }

    /**
     * 查找单个字段值（默认大小写敏感）
     *
     * @param json      JSON字符串
     * @param fieldName 目标字段名
     * @param type      返回值类型（Class形式）
     * @return 第一个匹配的字段值
     */
    public static <T> T findField(String json, String fieldName, Class<T> type) {
        return findField(json, fieldName, type, true);
    }

    /**
     * 查找单个字段值（可指定大小写敏感）
     *
     * @param json          JSON字符串
     * @param fieldName     目标字段名
     * @param type          返回值类型（Class形式）
     * @param caseSensitive 是否大小写敏感
     * @return 第一个匹配的字段值
     */
    public static <T> T findField(String json, String fieldName, Class<T> type, boolean caseSensitive) {
        List<JsonElement> elements = collectJsonElements(json, fieldName, caseSensitive);
        return elements.isEmpty() ? null : convertJsonElement(elements.get(0), type);
    }

    /**
     * 查找单个字段值（支持泛型类型）
     *
     * @param json      JSON字符串
     * @param fieldName 目标字段名
     * @param type      返回值类型（TypeToken形式）
     * @return 第一个匹配的字段值
     */
    public static <T> T findField(String json, String fieldName, Type type) {
        List<JsonElement> elements = collectJsonElements(json, fieldName, true);
        return elements.isEmpty() ? null : gson.fromJson(elements.get(0), type);
    }

    /**
     * 查找所有同名字段值
     *
     * @param json      JSON字符串
     * @param fieldName 目标字段名
     * @param type      返回值类型（Class形式）
     * @return 所有匹配字段值的列表
     */
    public static <T> List<T> findFields(String json, String fieldName, Class<T> type) {
        List<JsonElement> elements = collectJsonElements(json, fieldName, true);
        return convertElements(elements, type);
    }

    /**
     * 查找所有同名字段值（支持泛型类型）
     *
     * @param json      JSON字符串
     * @param fieldName 目标字段名
     * @param type      返回值类型（TypeToken形式）
     * @return 所有匹配字段值的列表
     */
    public static <T> List<T> findFields(String json, String fieldName, Type type) {
        List<JsonElement> elements = collectJsonElements(json, fieldName, true);
        List<T> results = new ArrayList<>();
        for (JsonElement element : elements) {
            results.add(gson.fromJson(element, type));
        }
        return results;
    }

    // ============== 核心递归实现 ==============

    /**
     * 收集匹配字段的JSON元素
     */
    private static List<JsonElement> collectJsonElements(String json, String fieldName, boolean caseSensitive) {
        JsonElement root = parseJson(json);
        List<JsonElement> results = new ArrayList<>();
        traverseJson(root, fieldName, caseSensitive, results);
        return results;
    }

    /**
     * JSON解析（带错误处理）
     */
    private static JsonElement parseJson(String json) {
        try {
            return JsonParser.parseString(json);
        } catch (JsonSyntaxException e) {
            throw new IllegalArgumentException("无效的JSON格式", e);
        }
    }

    /**
     * 递归遍历JSON元素
     */
    private static void traverseJson(JsonElement element, String targetKey,
                                     boolean caseSensitive, List<JsonElement> results) {

        if (element == null || element.isJsonNull()) {
            return;
        }

        // 处理JSON对象
        if (element.isJsonObject()) {
            JsonObject obj = element.getAsJsonObject();

            // 1. 遍历所有属性
            for (String key : obj.keySet()) {
                JsonElement value = obj.get(key);

                // 检查当前属性名是否匹配
                if (isKeyMatch(key, targetKey, caseSensitive)) {
                    results.add(value);
                }

                // 递归处理值（深度优先）
                traverseJson(value, targetKey, caseSensitive, results);
            }
        }
        // 处理JSON数组
        else if (element.isJsonArray()) {
            JsonArray array = element.getAsJsonArray();
            for (JsonElement item : array) {
                traverseJson(item, targetKey, caseSensitive, results);
            }
        }
    }

    /**
     * 键名匹配检测
     */
    private static boolean isKeyMatch(String actualKey, String targetKey, boolean caseSensitive) {
        return caseSensitive ?
                actualKey.equals(targetKey) :
                actualKey.equalsIgnoreCase(targetKey);
    }

    // ============== 类型转换工具 ==============

    /**
     * 转换JsonElement到指定类型
     */
    private static <T> T convertJsonElement(JsonElement element, Class<T> type) {
        if (element == null) return null;
        return gson.fromJson(element, type);
    }

    /**
     * 批量转换JsonElement列表
     */
    private static <T> List<T> convertElements(List<JsonElement> elements, Class<T> type) {
        List<T> results = new ArrayList<>();
        for (JsonElement element : elements) {
            results.add(convertJsonElement(element, type));
        }
        return results;
    }


}
